-- GetWorldDataMap(id):获取当前世界的数据map表  注意此表会在加载完成后自动加载，玩家修改后会自动保存
-- GetWorldDataList(id):获取当前世界的数据list表  注意此表会在加载完成后自动加载，玩家修改后会自动保存
-- GetMyData(id):获取某项设置的数据
-- SetMyData(id, value):设置某项设置的数据
-- AddPlayerLeaveFunc(func):添加离开服务器前执行的函数

-- 你可以在任意界面或者控制台使用 w_util = require("libs/worldmanager") 来获取该管理器！
-- 日志文件存储在 ShroomCakeFileSysLog.txt 文件中


local WM = {}
local file_sys = require "libs/filehandle"
local t_util = require "libs/tableutil"
local BOX_PREFIX,BOX_TAIL = "SRC_BOX_DATA_",".hxd"
local data_index = BOX_PREFIX .."0".. BOX_TAIL
local MAP_ID_PREFIX,List_ID_PREFIX,Line_ID_PREFIX = file_sys:GetPrefix()
local serverSeed
local w_util = require "libs/worldutil"
-- 获取服务器种子
function WM:GetServerSeed()
    if (not serverSeed) and TheWorld and TheWorld.net and TheWorld.net.components.shardstate then
        serverSeed = TheWorld.net.components.shardstate:GetMasterSessionId()
    end
    return serverSeed
end


local world_bind
local world_map = {}
local isnew         -- 不知道能否解决旧档数据复用的问题
-- 获取当前世界的数据存档文件名
function WM:GetWorldDir()
    if world_bind then
        return BOX_PREFIX..world_bind..BOX_TAIL
    end
end

local wold_data = {}
local function GetWorldData()
    if not next(wold_data) and not isnew then
        wold_data = file_sys:DataFromJsonLine(WM:GetWorldDir())
    end
    return wold_data
end

function WM:GetWorldDataMap(id)
    wold_data = GetWorldData()
    local id = MAP_ID_PREFIX..tostring(id)
    if type(wold_data[id]) ~= "table" then
        wold_data[id] = {}
    end
    return wold_data[id]
end
function WM:GetWorldDataList(id)
    wold_data = GetWorldData()
    local id = List_ID_PREFIX..tostring(id)
    if type(wold_data[id]) ~= "table" then
        wold_data[id] = {}
    end
    return wold_data[id]
end
function WM:GetWorldDataLine(id)
    wold_data = GetWorldData()
    local id = Line_ID_PREFIX..tostring(id)
    if type(wold_data[id]) ~= "table" then
        wold_data[id] = {}
    end
    return wold_data[id]
end


local function GetWorldBind()
    if world_bind then
        return world_bind
    end
    if not serverSeed then
        return
    end
    local world_list = {}
    world_list = file_sys:ListFromJsonLine(data_index)
    world_map = t_util:MapFromList(world_list)
    
    world_bind = world_map[serverSeed] and world_map[serverSeed].b
    local nowtime = os.time()
    if world_bind then
        world_map[serverSeed].e = nowtime
    else
        -- 最近玩的前20个保留
        table.sort(world_list, function(x, y)
            return (type(x.e) == "number" and x.e or 0) > (type(y.e) == "number" and y.e or 0)
        end)
        local world_map_recent = t_util:MapFromList(world_list, 20)
        -- 玩的最久的20个保留
        table.sort(world_list, function(x, y)
            return (type(x.a) == "number" and x.a or 0) > (type(y.a) == "number" and y.a or 0)
        end)
        local world_map_long = t_util:MapFromList(world_list, 20)

        -- 重新存储服务器数据
        local bind_used = {}
        for _, map in pairs({world_map_recent, world_map_long})do
            for key, value in pairs(map)do
                world_map[key] = value
                table.insert(bind_used, value.b)
            end
        end
        -- 将最新的存储下来
        for i = 1,41 do
            if not table.contains(bind_used, i) then
                world_map[serverSeed] = {
                    e = nowtime,
                    b = i,
                }
                break
            end
        end
        world_bind = world_map[serverSeed].b
        -- 删除旧档索引
        for seed, data in pairs(world_map)do
            if type(data) == "table" and data.b == world_bind and seed ~= serverSeed then
                world_map[seed] = nil
            end
        end
        isnew = true
    end
    return world_bind
end

local function Save()
    -- 将总游玩时间同步到目录中
    serverSeed = serverSeed or WM:GetServerSeed()
    if not serverSeed then
        return
    end
    local serverdata = world_map[serverSeed]
    if type(serverdata) ~= "table" or type(serverdata.e) ~= "number" then
        return file_sys:LogAddFile("存储数据时发生异常！", tostring(serverSeed), type(serverdata))
    end
    local nowtime = os.time()
    serverdata.a = (serverdata.a or 0) + (nowtime - (serverdata.e or nowtime))
    serverdata.e = nowtime
    file_sys:DataToJsonLine(data_index,world_map)
    -- 将服务器数据存储
    file_sys:FuckTableToDataFile(WM:GetWorldDir(),wold_data)

    -- file_sys:LogAddFile("日志已记录")
end

-- 警告：该方法被废弃，原因：只有多层世界才需要这个
-- function WM:GetWorldSeed()
--     return TheWorld and TheWorld.meta.session_identifier
-- end


-- 其实，也可以放在modmain中用AddSimPostInit判断
local __ConfirmPlayerInitializationTheLock
WM.Init = function()
    if __ConfirmPlayerInitializationTheLock then
        return
    end
    __ConfirmPlayerInitializationTheLock = true
    -- 玩家种子和世界种子赋值
    serverSeed = WM:GetServerSeed()
    if not serverSeed then
        return file_sys:LogAddFile("获取玩家种子失败！")
    end
    world_bind = GetWorldBind()
    if not world_bind then
        return file_sys:LogAddFile("无法分配数据存档！")
    end
    wold_data = GetWorldData()
    if not wold_data then
        return file_sys:LogAddFile("无法加载数据存档！")
    end
    if GetModConfigData("sw_memory", MOD_ShroomCake.Mod.name) ~= "startday" then
        w_util:SetBindState(TheWorld:HasTag("cave") and "startcaveday" or "startday", Save)
    end
    
    -- file_sys:LogAddFile("已完成加载")
end
WM.Init()


local funcs_player_leave = {}
function WM:AddPlayerLeaveFunc(func)
    if type(func) == "function" then
        table.insert(funcs_player_leave, func)
    end
end


local _DoRestart = DoRestart
function DoRestart(...)
    for _, func in pairs(funcs_player_leave)do
        func()
    end
    Save()
    return _DoRestart(...)
end
local _MigrateToServer = MigrateToServer
function MigrateToServer(ip, port, ...)
    for _, func in pairs(funcs_player_leave)do
        func()
    end
    Save()
    return _MigrateToServer(ip, port, ...)
end


return WM